﻿using Newtonsoft.Json.Linq;
using SharpDX;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Net.NetworkInformation;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
using System.Timers;
using System.Windows.Forms;
using System.Linq.Expressions;
using System.Windows.Media.Media3D;
using System.Windows.Threading;
using static 摸鱼.全局类;
using SharpCompress.Common;
using System.Diagnostics;

namespace 摸鱼
{
    /// <summary>
    /// 此工具用于模拟STA线程池, MoyuThreadPool启动的线程越多性能越好
    /// </summary>
    [SkipLocalsInit]
    public class MoyuThreadPool : SynchronizationContext
    {
        private readonly ConcurrentQueue<Moyuptr<SendOrPostCallback, object, ManualResetEventSlim>> 空闲线程 = new();
        public readonly int 初始线程ID = Thread.CurrentThread.ManagedThreadId;
        public static MoyuThreadPool 全局池;
        public static int maxThreadCount { get; private set; }

        private static object _starThreadCountobj = new();
        private static int _starThreadCount;
        public static int starThreadCount
        {
            get
            {
                lock (_starThreadCountobj)
                    return _starThreadCount;
            }
            private set
            {
                lock (_starThreadCountobj)
                    _starThreadCount = value;
            }
        }
        private bool 循环;
        public void Dispose()
        {
            Exit();
        }
        public MoyuThreadPool(int MaxThreadCount)
        {
            for (int i = 0; i < MaxThreadCount; i++)
            {
                System.Threading.Thread t1 = new(() =>
                {
                    SetSynContext();
                    Thread.CurrentThread.Priority = ThreadPriority.Lowest;
                    Run();
                }, int.MaxValue);
                t1.SetApartmentState(ApartmentState.STA);
                t1.IsBackground = true;
                t1.Start();
            }
            maxThreadCount = MaxThreadCount;
        }
        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public static Task Run(Action action)
        {
            TaskCompletionSource source = new();
            全局池.Add(o =>
            {
                action();
                source.SetResult();
            }, default);
            return source.Task;
        }
        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public static Task Delay(int ms)
        {
            return Run(() =>
            {
                if (ms < 1)
                    return;
                else
                    MoyuDelay.Star(ms);
            });
        }
        public void SetSynContext() => DispatcherSynchronizationContext.SetSynchronizationContext(this);
        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public override void Post(SendOrPostCallback d, object? o) => Add(d, o);
        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public static void Post(Action d) => 全局池.Add(o => d(), 0);
        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public static Task<T> Get<T>(Func<T> func)
        {
            TaskCompletionSource<T> source = new();
            全局池.Add(o => source.SetResult(func()), default);
            return source.Task;
        }
        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public void Add(SendOrPostCallback d, object? o)
        {
            if (空闲线程.TryDequeue(out var x))
            {
                x.Value1 = d;
                x.Value2 = o;
                x.Value3.Set();
            }
        }
        public void Run()
        {
            循环 = true;
            GetAction(out var 任务, out var 信号);
            while (循环)
            {
                信号.Wait();
                starThreadCount++;
                任务.Value1(任务.Value2);
                信号.Reset();
                starThreadCount--;
                空闲线程.Enqueue(任务);
            }
        }
        private void GetAction(out Moyuptr<SendOrPostCallback, object, ManualResetEventSlim> 任务, out ManualResetEventSlim 信号)
        {
            任务 = new() { Value3 = new(false) };
            信号 = 任务.Value3;
            空闲线程.Enqueue(任务);
        }
        private void Exit()
        {
            循环 = false;
            for (int i = 0; i < (空闲线程.Count * 2); i++)
                Add(o => 空(), 0);
        }
    }

    /// <summary>
    /// 此类必须与 MoyuContext 和 MoyuTask 绑定, 并且放在可访问位置, 是Timer的替代品, 解决了高延迟、不精确、单线程和多线程无法兼并的问题
    /// </summary>
    [SkipLocalsInit]
    public class MoyuTimer
    {
        public double 循环间隔;
        public int 首次间隔 = 0;
        public bool 重复;
        private bool Star = true;
        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public MoyuTimer(bool 重复, int 间隔)
        {
            this.重复 = 重复;
            this.循环间隔 = 间隔;
        }
        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public Task Run(Action 任务)
        {
            return MoyuThreadPool.Run(() =>
            {
                MoyuWait moyuWait = new(false);
                Star = true;
                moyuWait.Wait(首次间隔);
                double oldtime = 时间戳;
                while (Star)
                {
                    任务();
                    自旋(ref oldtime, ref 循环间隔);
                    if (!重复)
                        Star = false;
                }
            });
        }
        public void Exit() => Star = false;
    }
    /// <summary>
    /// 只要拿到Moyuptr实例, 从实例访问Value, 任何线程访问到的都是引用对象
    /// </summary>
    public class Moyuptr<T>
    {
        public Moyuptr() { }
        public Moyuptr(T value) => this.Value = value;
        public T Value = default;
        public override string? ToString() => Value?.ToString();
        public static implicit operator T(Moyuptr<T> 对象) => 对象.Value;
    }
    public class Moyuptr<T, R>
    {
        public T Value1 = default;
        public R Value2 = default;
        public Moyuptr() { }
        public Moyuptr(T Value1, R Value2)
        {
            this.Value1 = Value1;
            this.Value2 = Value2;
        }
    }
    public class Moyuptr<T, R, K>
    {
        public T Value1 = default;
        public R Value2 = default;
        public K Value3 = default;
        public Moyuptr() { }
        public Moyuptr(T Value1, R Value2, K Value3)
        {
            this.Value1 = Value1;
            this.Value2 = Value2;
            this.Value3 = Value3;
        }
    }



    public class MoyuWait
    {
        public bool IsSet;
        private Action action = default;
        private Func<object> func = default;

        public MoyuWait(bool 放行)
        {
            IsSet = 放行;
        }
        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public void Action()
        {
            if (action != null)
            {
                action();
                action = null;
            }
        }
        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public void Wait()
        {
            自旋(ref IsSet);
            IsSet = false;
            if (action != null)
            {
                action();
                action = null;
            }
        }
        /// <summary>
        /// false表示超时
        /// </summary>
        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public bool Wait(double ms)
        {
            double oldtime = 时间戳;
            if (ms > 0)
                自旋(ref IsSet, ref oldtime, ref ms);

            bool resul = IsSet;
            IsSet = false;
            if (action != null)
            {
                action();
                action = null;
            }
            return resul;
        }
        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public object Get()
        {
            Wait();
            if (func != null)
            {
                var 返回值 = func();
                func = null;
                return 返回值;
            }
            return default;
        }
        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public object Get(int ms)
        {
            Wait(ms);
            if (func != null)
            {
                var 返回值 = func();
                func = null;
                return 返回值;
            }
            return default;
        }
        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public void Set(Action action)
        {
            this.action = action;
            IsSet = true;
        }
        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public void NotSet(Action action)
        {
            this.action = action;
            IsSet = false;
        }
        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public void Set(Func<object> func)
        {
            this.func = func;
            IsSet = true;
        }
        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public void Reset() => IsSet = false;
        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public void Set() => IsSet = true;
        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public void IFEXIT()
        {
            if (action != null)
            {
                action();
                action = null;
            }
        }
        public void ExitThread() => Set(() => 返回顶级调用堆栈());



        //----------------------Timer-----------------------
        private bool Star;
        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public void ExitTimer() => Star = false;

        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public void Timer(Action 任务, double 循环间隔, double 首次间隔 = 0)
        {
            Star = true;
            Wait(首次间隔);
            double oldtime = 时间戳;
            while (Star)
            {
                任务();
                自旋(ref oldtime, ref 循环间隔);
                if (action != null)
                {
                    action();
                    action = null;
                }
            }
        }
    }

    [SkipLocalsInit]
    public sealed class MoyuDelay
    {
        private double 结束时间;
        private static System.Threading.Timer timer;
        private static readonly Queue<MoyuDelay> 队列 = new();
        private static readonly object timerLock = new object();

        public MoyuDelay(int ms) => 结束时间 = 时间戳 + ms;

        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public static void Dispose()
        {
            timer?.Dispose();
            timer = null;
            队列.Clear();
        }

        /// <summary>
        /// 精度约等于初始化时设置的 (1 到 时间精度值) 之间, 不过受CPU负载影响可能会超出这个范围
        /// </summary>
        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public static void Star(int ms)
        {
            MoyuDelay delayLook = new(ms);
            Monitor.Enter(timerLock);
            队列.Enqueue(delayLook);
            Monitor.Exit(timerLock);
            Monitor.Enter(delayLook);
            Monitor.Wait(delayLook);
            Monitor.Exit(delayLook);
        }

        public static void 初始化(int 时间精度 = 5)
        {
            if (timer != null)
                throw new InvalidOperationException("已经初始化过了");

            timer = new System.Threading.Timer(DoLoop, null, 0, 时间精度);
        }

        private static void DoLoop(object? o)
        {
            int count = 队列.Count + 1;
            while (count-- > 0)
            {
                Monitor.Enter(timerLock);
                if (!队列.TryDequeue(out var delayLook))
                {
                    Monitor.Exit(timerLock);
                    break;
                }
                Monitor.Exit(timerLock);

                if (时间戳 > delayLook.结束时间)
                {
                    Monitor.Enter(delayLook);
                    Monitor.Pulse(delayLook);
                    Monitor.Exit(delayLook);
                }
                else
                {
                    Monitor.Enter(timerLock);
                    队列.Enqueue(delayLook);
                    Monitor.Exit(timerLock);
                }
            }
        }
    }

    public static class MoyuRx
    {
        public static IObservable<T> AsyncObservable<T>(Func<T> value, int ms, out IDisposable disposable)
        {
            disposable = new _MoyuRx(ms);
            return _AsyncObservable(value, value(), (_MoyuRx)disposable).ToObservable();
        }
        private static async IAsyncEnumerable<T> _AsyncObservable<T>(Func<T> value, T oldvalue, _MoyuRx rx)
        {
            int ms = rx.ms;
            TaskCompletionSource<T> taskCompletion = new();
            MoyuThreadPool.Post(() =>
            {
                do
                {
                    while (EqualityComparer<T>.Default.Equals(value(), oldvalue))
                        MoyuDelay.Star(ms);
                    oldvalue = value();
                    taskCompletion.TrySetResult(oldvalue);
                } while (!rx.Stop);
            });
            while (!rx.Stop)
            {
                yield return await taskCompletion.Task;
                taskCompletion = new();
            }
        }
        private static IEnumerable<K> _BlockingObservable<K>(Func<K> value, K oldvalue, _MoyuRx rx)
        {
            int ms = rx.ms;
            do
            {
                while (EqualityComparer<K>.Default.Equals(value(), oldvalue))
                    MoyuDelay.Star(ms);
                oldvalue = value();
                yield return oldvalue;
            } while (!rx.Stop);
        }
        public static IObservable<K> BlockingObservable<K>(Func<K> value, int ms, out IDisposable disposable)
        {
            disposable = new _MoyuRx(ms);
            return _BlockingObservable(value, value(), (_MoyuRx)disposable).ToObservable();
        }
        private class _MoyuRx : IDisposable
        {
            public bool Stop;
            public int ms;
            public void Dispose()
            {
                Stop = true;
            }
            public _MoyuRx(int ms)
            {
                this.ms = ms;
            }
        }
    }



    [SkipLocalsInit]
    public class BlockingQueue<T> : IDisposable
    {
        private Dictionary<MoyuWait, ConcurrentQueue<(T 消息, double 记录时间)>> Values = new();
        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public T 订阅(MoyuWait wait, double ms)
        {
            Values.TryAdd(wait, new());
        循环:
            过滤消息(Values[wait], ms);
            if (Values.Count == 0)
                wait.Reset();
            wait.Wait();
            if (Values[wait].TryDequeue(out var item))
                return item.消息;
            else
                goto 循环;

            void 过滤消息(ConcurrentQueue<(T 消息, double 记录时间)> values, double ms)
            {
                int i = values.Count;
                double 时间线 = 时间戳 - ms;
                while (i-- > 0 && values.TryDequeue(out var item))
                {
                    if (item.记录时间 > 时间线)
                        values.Enqueue(item);
                }
            }
        }
        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public void 传播(T item)
        {
            foreach (var valueitm in Values)
            {
                valueitm.Value.Enqueue((item, 时间戳));
                valueitm.Key.Set();
            }
        }
        public void Dispose()
        {
            foreach (var valueitm in Values)
                valueitm.Value.Clear();
            Values.Clear();
            Values = null;
        }
    }

    public class ThreadDoublebuffering
    {
        private SemaphoreSlim 单行道 = new(1, 1);
        private SemaphoreSlim 双行道 = new(2, 2);

        public void Enqueue(Action action)
        {
            MoyuThreadPool.Post(() =>
            {
                if (双行道.Wait(0))
                {
                    单行道.Wait();
                    try
                    {
                        action();
                    }
                    finally
                    {
                        双行道.Release();
                        单行道.Release();
                    }
                }
            });
        }
    }

    /// <summary>
    /// 多线程进入时，会刷新第一个等待线程的等待时间，后续线程会跳过等待并返回false
    /// </summary>
    public class OneThread
    {
        private AutoResetEvent autoReset = new(true);
        private double newtime = 0.0;
        public bool Wait(int ms)
        {
            newtime = 时间戳();
            if (autoReset.WaitOne(0))
            {
                SpinWait.SpinUntil(() => 时间戳() - newtime > ms);
                autoReset.Set();
                return true;
            }
            return false;
            double 时间戳() => Stopwatch.GetTimestamp() * 0.0001;
        }
    }












}
